AsyncLocalStorageã§Node.jsã®ãªã¯ãšã¹ãã¹ã³ãŒã倿°ç®¡çãç¿åŸãããããããªãªã³ã°ãè§£æ¶ããã¯ãªãŒã³ã§èŠ³æž¬æ§ã®é«ãã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã
JavaScriptéåæã³ã³ããã¹ããè§£ãæããïŒãªã¯ãšã¹ãã¹ã³ãŒãã®å€æ°ç®¡çã®åŸ¹åºè§£èª¬
çŸä»£ã®ãµãŒããŒãµã€ãéçºã®äžçã§ã¯ãç¶æ 管çã¯åºæ¬çãªèª²é¡ã§ããNode.jsãæ±ãéçºè ã«ãšã£ãŠããã®èª²é¡ã¯ãã®ã·ã³ã°ã«ã¹ã¬ããããã³ããããã³ã°ãéåæãšããæ§è³ªã«ãã£ãŠããã«å¢å¹ ãããŸãããã®ã¢ãã«ã¯ãI/OããŠã³ããªé«æ§èœã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããäžã§éåžžã«åŒ·åã§ãããç¹æã®åé¡ãåŒãèµ·ãããŸããããã«ãŠã§ã¢ããããŒã¿ããŒã¹ã¯ãšãªããµãŒãããŒãã£APIåŒã³åºãã«è³ããŸã§ãç¹å®ã®ãªã¯ãšã¹ããæ§ã ãªéåææäœãééããéã«ããã®ã³ã³ããã¹ããã©ã®ããã«ç¶æããã°ããã®ã§ããããïŒãããŠãŒã¶ãŒã®ãªã¯ãšã¹ãããã®ããŒã¿ããå¥ã®ãŠãŒã¶ãŒã®ãªã¯ãšã¹ãã«æŒãåºããªãããã«ããã«ã¯ã©ãããã°ããã®ã§ããããïŒ
é·å¹ŽãJavaScriptã³ãã¥ããã£ã¯ãã®åé¡ã«åãçµãã§ããŸããããå€ãã®å Žåãããããããªãªã³ã°ãã®ãããªé¢åãªãã¿ãŒã³ã«é Œã£ãŠããŸãããããã¯ããŠãŒã¶ãŒIDããã¬ãŒã¹IDã®ãããªãªã¯ãšã¹ãåºæã®ããŒã¿ããã³ãŒã«ãã§ãŒã³å ã®ãã¹ãŠã®é¢æ°ã«æž¡ããŠããææ³ã§ãããã®ã¢ãããŒãã¯ã³ãŒããç ©éã«ããã¢ãžã¥ãŒã«éã®å¯çµåãçã¿åºããã¡ã³ããã³ã¹ãç¹°ãè¿ãããæªå€¢ã«ããŸãã
ããã§ç»å Žããã®ãéåæã³ã³ããã¹ãã§ããããã¯ããã®é·å¹Žã®åé¡ã«å¯Ÿããå
ç¢ãªè§£æ±ºçãæäŸããæŠå¿µã§ããNode.jsã§å®å®çã®AsyncLocalStorage APIãå°å
¥ãããããšã§ãéçºè
ã¯ãªã¯ãšã¹ãã¹ã³ãŒãã®å€æ°ããšã¬ã¬ã³ããã€å¹ççã«ç®¡çããããã®åŒ·åãªçµã¿èŸŒã¿ã¡ã«ããºã ãæã«å
¥ããŸããããã®ã¬ã€ãã§ã¯ãJavaScriptã®éåæã³ã³ããã¹ãã®äžçãå
æ¬çã«æ¢æ±ããåé¡ã説æãã解決çã玹ä»ããããã¹ã±ãŒã©ãã«ã§ä¿å®æ§ãé«ãã芳枬å¯èœæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãã°ããŒãã«ãªãŠãŒã¶ãŒããŒã¹åãã«æ§ç¯ããããã®å®è·µçãªå®äžçã§ã®äŸãæäŸããŸãã
äžå¿çãªèª²é¡ïŒäžŠè¡ã»éåæãªäžçã§ã®ç¶æ 管ç
ãã®è§£æ±ºçãååã«è©äŸ¡ããããã«ã¯ããŸãåé¡ã®æ·±ããçè§£ããªããã°ãªããŸãããNode.jsãµãŒããŒã¯ãäœåãã®åæãªã¯ãšã¹ããåŠçããŸãããªã¯ãšã¹ãAãå°çãããšãNode.jsã¯ãã®åŠçãéå§ããããŒã¿ããŒã¹ã¯ãšãªã®å®äºãåŸ ã€ããã«äžæåæ¢ããããšããããŸããåŸ æ©äžã«ããªã¯ãšã¹ãBãåãåã£ãŠãã®åŠçãéå§ããŸãããªã¯ãšã¹ãAã®ããŒã¿ããŒã¹çµæãè¿ã£ãŠãããšãNode.jsã¯ãã®å®è¡ãåéããŸãããã®çµ¶ãéãªãã³ã³ããã¹ãã¹ã€ããã³ã°ããã®ããã©ãŒãã³ã¹ã®ç§å¯ã§ãããããã¯åŸæ¥ã®ã¹ããŒã管çæè¡ã«å€§æ··ä¹±ããããããŸãã
ã°ããŒãã«å€æ°ã倱æããçç±
åå¿è ã®éçºè ãæåã«æãã€ãã®ã¯ãã°ããŒãã«å€æ°ã䜿çšããããšãããããŸãããäŸãã°ïŒ
let currentUser; // ã°ããŒãã«å€æ°
// ãŠãŒã¶ãŒãèšå®ããããã«ãŠã§ã¢
app.use((req, res, next) => {
currentUser = await getUserFromDb(req.headers.authorization);
next();
});
// ã¢ããªã±ãŒã·ã§ã³ã®å¥¥æ·±ãã«ãããµãŒãã¹é¢æ°
function logActivity() {
console.log(`Activity for user: ${currentUser.id}`);
}
ããã¯ã䞊è¡ç°å¢ã«ãããèŽåœçãªèšèšäžã®æ¬ é¥ã§ãããªã¯ãšã¹ãAãcurrentUserãèšå®ãããã®åŸéåææäœãåŸ
æ©ããŠããéã«ããªã¯ãšã¹ãBãå²ã蟌ãã§ããŠããªã¯ãšã¹ãAãçµäºããåã«currentUserãäžæžãããŠããŸãå¯èœæ§ããããŸãããªã¯ãšã¹ãAãåéãããšãã誀ã£ãŠãªã¯ãšã¹ãBã®ããŒã¿ã䜿çšããŠããŸããŸããããã¯äºæž¬äžå¯èœãªãã°ãããŒã¿ã®ç Žæãã»ãã¥ãªãã£ã®è匱æ§ãåŒãèµ·ãããŸããã°ããŒãã«å€æ°ã¯ãªã¯ãšã¹ãã»ãŒãã§ã¯ãããŸããã
ããããããªãªã³ã°ã®èŠç
ããäžè¬çã§å®å šãªåé¿çã¯ããããããããªãªã³ã°ããŸãã¯ããã©ã¡ãŒã¿æž¡ããã§ãããããã¯ãã³ã³ããã¹ããå¿ èŠãšãããã¹ãŠã®é¢æ°ã«åŒæ°ãšããŠæç€ºçã«æž¡ãããšãå«ã¿ãŸãã
ã¢ããªã±ãŒã·ã§ã³å
šäœã§ãã®ã³ã°çšã®ãŠããŒã¯ãªtraceIdãšãèªå¯çšã®userãªããžã§ã¯ããå¿
èŠã ãšæ³åããŠã¿ãŸãããã
ããããããªãªã³ã°ã®äŸïŒ
// 1. ãšã³ããªãŒãã€ã³ãïŒããã«ãŠã§ã¢
app.use((req, res, next) => {
const traceId = generateTraceId();
const user = { id: 'user-123', locale: 'en-GB' };
const requestContext = { traceId, user };
processOrder(requestContext, req.body.orderId);
});
// 2. ããžãã¹ããžãã¯å±€
function processOrder(context, orderId) {
log('Processing order', context);
const orderDetails = getOrderDetails(context, orderId);
// ... more logic
}
// 3. ããŒã¿ã¢ã¯ã»ã¹å±€
function getOrderDetails(context, orderId) {
log(`Fetching order ${orderId}`, context);
return db.query('SELECT * FROM orders WHERE id = ?', orderId);
}
// 4. ãŠãŒãã£ãªãã£å±€
function log(message, context) {
console.log(`[${context.traceId}] [User: ${context.user.id}] - ${message}`);
}
ããã¯æ©èœããäžŠè¡æ§ã®åé¡ãããå®å šã§ãããéå€§ãªæ¬ ç¹ããããŸãïŒ
- ã³ãŒãã®ç
©éãïŒ
contextãªããžã§ã¯ãã¯ããããçŽæ¥äœ¿çšããªãããåŒã³åºã颿°ã«æž¡ãå¿ èŠããã颿°ã«ããè³ãæã§æž¡ãããŸãã - å¯çµåïŒ ãã¹ãŠã®é¢æ°ã·ã°ããã£ã
contextãªããžã§ã¯ãã®åœ¢ç¶ã«çµåãããŸããã³ã³ããã¹ãã«æ°ããããŒã¿ïŒäŸïŒA/Bãã¹ããã©ã°ïŒã远å ããå¿ èŠãããå Žåãã³ãŒãããŒã¹å šäœã§æ°åã®é¢æ°ã·ã°ããã£ã倿Žããªããã°ãªããªããããããŸããã - å¯èªæ§ã®äœäžïŒ 颿°ã®äž»èŠãªç®çããã³ã³ããã¹ããæž¡ããŸããå®åçãªã³ãŒãã«ãã£ãŠææ§ã«ãªãå¯èœæ§ããããŸãã
- ã¡ã³ããã³ã¹ã®è² æ ïŒ ãªãã¡ã¯ã¿ãªã³ã°ãéå±ã§ãšã©ãŒãçºçããããããã»ã¹ã«ãªããŸãã
ç§ãã¡ã¯ããè¯ãæ¹æ³ãå¿ èŠãšããŠããŸããããªã¯ãšã¹ãåºæã®ããŒã¿ãä¿æãããã®ãªã¯ãšã¹ãã®éåæã³ãŒã«ãã§ãŒã³å ã®ã©ãããã§ãæç€ºçãªåãæž¡ããªãã§ã¢ã¯ã»ã¹ã§ãããéæ³ã®ãã³ã³ãããæã€æ¹æ³ã§ãã
`AsyncLocalStorage`ã®ç»å ŽïŒçŸä»£çãªè§£æ±ºç
Node.js v13.10.0以éã®å®å®æ©èœã§ããAsyncLocalStorageã¯ã©ã¹ã¯ããã®åé¡ã«å¯Ÿããå
¬åŒã®çãã§ããããã«ãããéçºè
ã¯ç¹å®ã®éå§ç¹ããéå§ãããéåææäœã®ãã§ãŒã³å
šäœã§æç¶ãããéé¢ãããã¹ãã¬ãŒãžã³ã³ããã¹ããäœæã§ããŸãã
ããã¯ãJavaScriptã®éåæã§ã€ãã³ãé§åãªäžçã®ããã®ãã¹ã¬ããããŒã«ã«ã¹ãã¬ãŒãžãã®äžåœ¢æ
ãšèããããšãã§ããŸããAsyncLocalStorageã³ã³ããã¹ãå
ã§æäœãéå§ãããšããã®æç¹ããåŒã³åºããããã¹ãŠã®é¢æ°ïŒåæãã³ãŒã«ããã¯ããŒã¹ããŸãã¯PromiseããŒã¹ã§ããïŒãããã®ã³ã³ããã¹ãã«ä¿åãããããŒã¿ã«ã¢ã¯ã»ã¹ã§ããŸãã
ã³ã¢APIã®æŠå¿µ
APIã¯éåžžã«ã·ã³ãã«ãã€åŒ·åã§ãã以äžã®3ã€ã®äž»èŠãªã¡ãœãããäžå¿ã«å±éããŸãïŒ
new AsyncLocalStorage(): ã¹ãã¢ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããŸããéåžžãã³ã³ããã¹ãã®çš®é¡ããšã«1ã€ã®ã€ã³ã¹ã¿ã³ã¹ïŒäŸïŒãã¹ãŠã®HTTPãªã¯ãšã¹ãçšã«1ã€ïŒãäœæããã¢ããªã±ãŒã·ã§ã³å šäœã§å ±æããŸããals.run(store, callback): ãããäžå¿çãªã¡ãœããã§ãã颿°ïŒcallbackïŒãå®è¡ããæ°ããéåæã³ã³ããã¹ãã確ç«ããŸããæåã®åŒæ°storeã¯ããã®ã³ã³ããã¹ãå ã§å©çšå¯èœã«ãããããŒã¿ã§ããcallbackå ã§å®è¡ããããã¹ãŠã®ã³ãŒãïŒéåææäœãå«ãïŒã¯ããã®storeã«ã¢ã¯ã»ã¹ã§ããŸããals.getStore(): ãã®ã¡ãœããã¯ãçŸåšã®ã³ã³ããã¹ãããããŒã¿ïŒstoreïŒãååŸããããã«äœ¿çšãããŸããrun()ã«ãã£ãŠç¢ºç«ãããã³ã³ããã¹ãã®å€ã§åŒã³åºãããå Žåãundefinedãè¿ããŸãã
å®è·µçãªå®è£ ïŒã¹ããããã€ã¹ãããã¬ã€ã
åã®ããããããªãªã³ã°ã®äŸãAsyncLocalStorageã䜿ã£ãŠãªãã¡ã¯ã¿ãªã³ã°ããŠã¿ãŸããããæšæºçãªExpress.jsãµãŒããŒã䜿çšããŸãããååã¯ã©ã®Node.jsãã¬ãŒã ã¯ãŒã¯ããã€ãã£ãã®httpã¢ãžã¥ãŒã«ã§ãåãã§ãã
ã¹ããã1ïŒäžå€®ã®`AsyncLocalStorage`ã€ã³ã¹ã¿ã³ã¹ãäœæãã
ã¹ãã¢ã®åäžã®å
±æã€ã³ã¹ã¿ã³ã¹ãäœæããã¢ããªã±ãŒã·ã§ã³å
šäœã§äœ¿çšã§ããããã«ãšã¯ã¹ããŒãããã®ããã¹ããã©ã¯ãã£ã¹ã§ããasyncContext.jsãšããååã®ãã¡ã€ã«ãäœæããŸãããã
// asyncContext.js
import { AsyncLocalStorage } from 'async_hooks';
export const requestContextStore = new AsyncLocalStorage();
ã¹ããã2ïŒããã«ãŠã§ã¢ã§ã³ã³ããã¹ãã確ç«ãã
ã³ã³ããã¹ããéå§ããã®ã«çæ³çãªå Žæã¯ããªã¯ãšã¹ãã®ã©ã€ããµã€ã¯ã«ã®ãŸãã«å§ãŸãã§ããããã«ãŠã§ã¢ã¯ããã«æé©ã§ãããªã¯ãšã¹ãåºæã®ããŒã¿ãçæããæ®ãã®ãªã¯ãšã¹ãåŠçããžãã¯ãals.run()ã§ã©ããããŸãã
// server.js
import express from 'express';
import { requestContextStore } from './asyncContext.js';
import { v4 as uuidv4 } from 'uuid'; // ãŠããŒã¯ãªtraceIdãçæãããã
const app = express();
// éæ³ã®ããã«ãŠã§ã¢
app.use((req, res, next) => {
const traceId = req.headers['x-request-id'] || uuidv4();
const user = { id: 'user-123', locale: 'en-GB' }; // å®éã®ã¢ããªã§ã¯ãããã¯èªèšŒããã«ãŠã§ã¢ããååŸããŸã
const store = { traceId, user };
// ãã®ãªã¯ãšã¹ãã®ã³ã³ããã¹ãã確ç«
requestContextStore.run(store, () => {
next();
});
});
// ... ã«ãŒããä»ã®ããã«ãŠã§ã¢ã¯ããã«èšè¿°
ãã®ããã«ãŠã§ã¢ã§ã¯ããã¹ãŠã®åä¿¡ãªã¯ãšã¹ãã«å¯ŸããŠtraceIdãšuserãå«ãstoreãªããžã§ã¯ããäœæããŸããæ¬¡ã«requestContextStore.run(store, ...)ãåŒã³åºããŸããå
éšã®next()åŒã³åºãã«ããããã®ç¹å®ã®ãªã¯ãšã¹ãã«å¯ŸããåŸç¶ã®ãã¹ãŠã®ããã«ãŠã§ã¢ãšã«ãŒããã³ãã©ãããã®æ°ããäœæãããã³ã³ããã¹ãå
ã§å®è¡ãããããšãä¿èšŒãããŸãã
ã¹ããã3ïŒã©ãããã§ãã³ã³ããã¹ãã«ã¢ã¯ã»ã¹ïŒããããããªãªã³ã°äžèŠïŒ
ããã§ãä»ã®ã¢ãžã¥ãŒã«ã¯æ ¹æ¬çã«ç°¡çŽ åã§ããŸãããã¯ãcontextãã©ã¡ãŒã¿ã¯å¿
èŠãããŸãããåã«requestContextStoreãã€ã³ããŒãããgetStore()ãåŒã³åºãã ãã§ãã
ãªãã¡ã¯ã¿ãªã³ã°ããããã®ã³ã°ãŠãŒãã£ãªãã£ïŒ
// logger.js
import { requestContextStore } from './asyncContext.js';
export function log(message) {
const context = requestContextStore.getStore();
if (context) {
const { traceId, user } = context;
console.log(`[${traceId}] [User: ${user.id}] - ${message}`);
} else {
// ãªã¯ãšã¹ãã³ã³ããã¹ãå€ã®ãã°ã®ããã®ãã©ãŒã«ããã¯
console.log(`[NO_CONTEXT] - ${message}`);
}
}
ãªãã¡ã¯ã¿ãªã³ã°ãããããžãã¹å±€ãšããŒã¿å±€ïŒ
// orderService.js
import { log } from './logger.js';
import * as db from './database.js';
export function processOrder(orderId) {
log('Processing order'); // ã³ã³ããã¹ãã¯äžèŠïŒ
const orderDetails = getOrderDetails(orderId);
// ... more logic
}
function getOrderDetails(orderId) {
log(`Fetching order ${orderId}`); // ãã¬ãŒãèªåçã«ã³ã³ããã¹ããååŸããŸã
return db.query('SELECT * FROM orders WHERE id = ?', orderId);
}
ãã®éãã¯æŽç¶ã§ããã³ãŒãã¯åçã«ã¯ãªãŒã³ã«ãªããå¯èªæ§ãåäžããã³ã³ããã¹ãã®æ§é ããå®å šã«åé¢ãããŸããããã®ã³ã°ãŠãŒãã£ãªãã£ãããžãã¹ããžãã¯ãããŒã¿ã¢ã¯ã»ã¹å±€ã¯ãä»ãçŽç²ã§ããããã®ç¹å®ã®ã¿ã¹ã¯ã«éäžããŠããŸãããªã¯ãšã¹ãã³ã³ããã¹ãã«æ°ããããããã£ã远å ããå¿ èŠãããå Žåããããäœæãããããã«ãŠã§ã¢ã倿Žããã ãã§æžã¿ãŸããä»ã®é¢æ°ã·ã°ããã£ã«è§Šããå¿ èŠã¯äžåãããŸããã
é«åºŠãªãŠãŒã¹ã±ãŒã¹ãšã°ããŒãã«ãªèŠç¹
ãªã¯ãšã¹ãã¹ã³ãŒãã®ã³ã³ããã¹ãã¯ããã®ã³ã°ã ãã®ããã®ãã®ã§ã¯ãããŸãããæŽç·Žãããã°ããŒãã«ãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«äžå¯æ¬ ãªãããŸããŸãªåŒ·åãªãã¿ãŒã³ãå¯èœã«ããŸãã
1. 忣ãã¬ãŒã·ã³ã°ãšèŠ³æž¬å¯èœæ§
ãã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ã§ã¯ãåäžã®ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ãè€æ°ã®ãµãŒãã¹ã«ãããäžé£ã®ãªã¯ãšã¹ããåŒãèµ·ããããšããããŸããåé¡ããããã°ããã«ã¯ããã®å
šäœçãªè¡çšã远跡ã§ããå¿
èŠããããŸããAsyncLocalStorageã¯ãçŸä»£çãªãã¬ãŒã·ã³ã°ã®ç€ã§ããAPIã²ãŒããŠã§ã€ãžã®åä¿¡ãªã¯ãšã¹ãã«ãŠããŒã¯ãªtraceIdãå²ãåœãŠãããšãã§ããŸãããã®IDã¯éåæã³ã³ããã¹ãã«ä¿åãããããŠã³ã¹ããªãŒã ãµãŒãã¹ãžã®ãã¹ãŠã®ã¢ãŠãããŠã³ãAPIåŒã³åºãïŒäŸïŒHTTPããããŒãšããŠïŒã«èªåçã«å«ãŸããŸããåãµãŒãã¹ãåæ§ã«ã³ã³ããã¹ããäŒæããŸããäžå€®éæš©åã®ãã®ã³ã°ãã©ãããã©ãŒã ã¯ããããã®ãã°ãåã蟌ã¿ãã·ã¹ãã å
šäœã«ããããªã¯ãšã¹ãã®ãšã³ãããŒãšã³ãã®ãããŒå
šäœãåæ§ç¯ã§ããŸãã
2. åœéåïŒi18nïŒãšå°ååïŒl10nïŒ
ã°ããŒãã«ãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ãæ¥ä»ãæå»ãæ°å€ãé貚ããŠãŒã¶ãŒã®ããŒã«ã«åœ¢åŒã§è¡šç€ºããããšãäžå¯æ¬ ã§ãããŠãŒã¶ãŒã®ãã±ãŒã«ïŒäŸïŒ'fr-FR', 'ja-JP', 'en-US'ïŒããªã¯ãšã¹ãããããŒããŠãŒã¶ãŒãããã¡ã€ã«ããååŸããéåæã³ã³ããã¹ãã«ä¿åã§ããŸãã
// é貚ããã©ãŒããããããŠãŒãã£ãªãã£
import { requestContextStore } from './asyncContext.js';
function formatCurrency(amount, currencyCode) {
const context = requestContextStore.getStore();
const locale = context?.user?.locale || 'en-US'; // ããã©ã«ããžã®ãã©ãŒã«ããã¯
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: currencyCode,
}).format(amount);
}
// ã¢ããªã®å¥¥æ·±ãã§ã®äœ¿çšäŸ
const priceString = formatCurrency(199.99, 'EUR'); // èªåçã«ãŠãŒã¶ãŒã®ãã±ãŒã«ã䜿çš
ããã«ãããlocale倿°ãè³ãæã«æž¡ãããšãªããäžè²«ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãä¿èšŒãããŸãã
3. ããŒã¿ããŒã¹ãã©ã³ã¶ã¯ã·ã§ã³ç®¡ç
åäžã®ãªã¯ãšã¹ãã§ãæåãŸãã¯å€±æãäžäœã§ãªããã°ãªããªãè€æ°ã®ããŒã¿ããŒã¹æžã蟌ã¿ãå®è¡ããå¿ èŠãããå Žåããã©ã³ã¶ã¯ã·ã§ã³ãå¿ èŠã§ãããªã¯ãšã¹ããã³ãã©ã®éå§æã«ãã©ã³ã¶ã¯ã·ã§ã³ãéå§ãããã©ã³ã¶ã¯ã·ã§ã³ã¯ã©ã€ã¢ã³ããéåæã³ã³ããã¹ãã«ä¿åããããšã§ããã®ãªã¯ãšã¹ãå ã®åŸç¶ã®ãã¹ãŠã®ããŒã¿ããŒã¹åŒã³åºããèªåçã«åããã©ã³ã¶ã¯ã·ã§ã³ã¯ã©ã€ã¢ã³ãã䜿çšããããã«ãªããŸãããã³ãã©ã®æåŸã«ãçµæã«åºã¥ããŠãã©ã³ã¶ã¯ã·ã§ã³ãã³ããããŸãã¯ããŒã«ããã¯ã§ããŸãã
4. ãã£ãŒãã£ãŒãã°ã«ãšA/Bãã¹ã
ãªã¯ãšã¹ãã®éå§æã«ããŠãŒã¶ãŒãã©ã®ãã£ãŒãã£ãŒãã©ã°ãŸãã¯A/Bãã¹ãã°ã«ãŒãã«å±ããŠãããã倿ãããã®æ å ±ãã³ã³ããã¹ãã«ä¿åã§ããŸããAPIå±€ããã¬ã³ããªã³ã°å±€ãŸã§ãã¢ããªã±ãŒã·ã§ã³ã®ããŸããŸãªéšåãã³ã³ããã¹ããåç §ããŠãã©ã®ããŒãžã§ã³ã®æ©èœãå®è¡ããããã©ã®UIã衚瀺ããããæ±ºå®ã§ããè€éãªãã©ã¡ãŒã¿æž¡ããªãã§ããŒãœãã©ã€ãºããããšã¯ã¹ããªãšã³ã¹ãäœæã§ããŸãã
ããã©ãŒãã³ã¹ã«é¢ããèæ ®äºé ãšãã¹ããã©ã¯ãã£ã¹
ãããã質åã¯ãããã©ãŒãã³ã¹ã®ãªãŒããŒãããã¯ã©ã®ããããïŒãšãããã®ã§ããNode.jsã³ã¢ããŒã ã¯ãAsyncLocalStorageãéåžžã«å¹ççã«ããããã«å€å€§ãªåªåãæã£ãŠããŸãããããã¯C++ã¬ãã«ã®async_hooks APIã®äžã«æ§ç¯ãããŠãããV8 JavaScriptãšã³ãžã³ãšæ·±ãçµ±åãããŠããŸãã倧倿°ã®Webã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠãããã©ãŒãã³ã¹ãžã®åœ±é¿ã¯ç¡èŠã§ããçšåºŠã§ãããã³ãŒãã®å質ãšä¿å®æ§ã®é£èºçãªåäžã«ãã£ãŠååã«çžæ®ºãããŸãã
广çã«äœ¿çšããããã«ã¯ã以äžã®ãã¹ããã©ã¯ãã£ã¹ã«åŸã£ãŠãã ããïŒ
- ã·ã³ã°ã«ãã³ã€ã³ã¹ã¿ã³ã¹ã䜿çšããïŒ ç§ãã¡ã®äŸã§ç€ºããããã«ãäžè²«æ§ã確ä¿ããããã«ããªã¯ãšã¹ãã³ã³ããã¹ãçšã«åäžã®ãšã¯ã¹ããŒãããã
AsyncLocalStorageã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã - ãšã³ããªãŒãã€ã³ãã§ã³ã³ããã¹ãã確ç«ããïŒ åžžã«ãããã¬ãã«ã®ããã«ãŠã§ã¢ããªã¯ãšã¹ããã³ãã©ã®åé ã§
als.run()ãåŒã³åºããŸããããã«ãããã³ã³ããã¹ãã®æç¢ºã§äºæž¬å¯èœãªå¢çãäœæãããŸãã - ã¹ãã¢ãã€ãã¥ãŒã¿ãã«ãšããŠæ±ãïŒ ã¹ãã¢ãªããžã§ã¯ãèªäœã¯ãã¥ãŒã¿ãã«ã§ãããã€ãã¥ãŒã¿ãã«ãšããŠæ±ãã®ãè¯ãç¿æ
£ã§ãããªã¯ãšã¹ãã®éäžã§ããŒã¿ã远å ããå¿
èŠãããå Žåã¯ãå¥ã®
run()åŒã³åºãã§ãã¹ããããã³ã³ããã¹ããäœæããæ¹ãã¯ãªãŒã³ãªå Žåãå€ãã§ãããããã¯ããé«åºŠãªãã¿ãŒã³ã§ãã - ã³ã³ããã¹ãããªãå ŽåãåŠçããïŒ ãã¬ãŒã§ç€ºããããã«ããŠãŒãã£ãªãã£ã¯åžžã«
getStore()ãundefinedãè¿ããã©ããããã§ãã¯ãã¹ãã§ããããã«ãããããã¯ã°ã©ãŠã³ãã¹ã¯ãªãããã¢ããªã±ãŒã·ã§ã³ã®èµ·åæãªã©ããªã¯ãšã¹ãã³ã³ããã¹ãã®å€ã§å®è¡ãããå Žåã§ãæ£åžžã«æ©èœããŸãã - ãšã©ãŒåŠçã¯ãã®ãŸãŸæ©èœããïŒ éåæã³ã³ããã¹ãã¯ã
Promiseãã§ãŒã³ã.then()/.catch()/.finally()ãããã¯ãããã³async/awaitãštry/catchãä»ããŠæ£ããäŒæããŸããç¹å¥ãªããšãããå¿ èŠã¯ãããŸããããšã©ãŒãã¹ããŒãããŠããã³ã³ããã¹ãã¯ãšã©ãŒåŠçããžãã¯å ã§å©çšå¯èœãªãŸãŸã§ãã
çµè«ïŒNode.jsã¢ããªã±ãŒã·ã§ã³ã®æ°æä»£
AsyncLocalStorageã¯åãªã䟿å©ãªãŠãŒãã£ãªãã£ä»¥äžã®ãã®ã§ããããµãŒããŒãµã€ãJavaScriptã«ãããç¶æ
管çã®ãã©ãã€ã ã·ãããæå³ããŸããããã¯ãéåžžã«äžŠè¡æ§ã®é«ãç°å¢ã§ãªã¯ãšã¹ãã¹ã³ãŒãã®ã³ã³ããã¹ãã管çãããšããé·å¹Žã®åé¡ã«å¯Ÿãããã¯ãªãŒã³ã§å
ç¢ããã€é«æ§èœãªè§£æ±ºçãæäŸããŸãã
ãã®APIãæ¡çšããããšã§ã以äžã®ããšãå¯èœã«ãªããŸãïŒ
- ããããããªãªã³ã°ãæé€ããïŒ ããã¯ãªãŒã³ã§ãçŠç¹ãçµã£ã颿°ãæžãã
- ã¢ãžã¥ãŒã«ãåé¢ããïŒ äŸåé¢ä¿ãæžãããã³ãŒãã®ãªãã¡ã¯ã¿ãªã³ã°ãšãã¹ãã容æã«ããã
- 芳枬å¯èœæ§ãåäžãããïŒ åŒ·åãªåæ£ãã¬ãŒã·ã³ã°ãšã³ã³ããã¹ãä»ããã®ã³ã°ã容æã«å®è£ ããã
- æŽç·Žãããæ©èœãæ§ç¯ããïŒ ãã©ã³ã¶ã¯ã·ã§ã³ç®¡çãåœéåã®ãããªè€éãªãã¿ãŒã³ãç°¡çŽ åããã
Node.jsã§çŸä»£çã§ã¹ã±ãŒã©ãã«ããã€ã°ããŒãã«ãæèããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéçºè
ã«ãšã£ãŠãéåæã³ã³ããã¹ãããã¹ã¿ãŒããããšã¯ãã¯ãä»»æã§ã¯ãªããå¿
é ã®ã¹ãã«ã§ããæä»£é
ãã®ãã¿ãŒã³ããè±åŽããAsyncLocalStorageãæ¡çšããããšã§ãããå¹ççã§ããã ãã§ãªããã¯ããã«ãšã¬ã¬ã³ãã§ä¿å®æ§ã®é«ãã³ãŒããæžãããšãã§ããŸãã